home *** CD-ROM | disk | FTP | other *** search
- /*______________________________________________________*/
- /* Sound Demo */
- /* by */
- /* RICHARD P. COLLYER */
- /* Developer Technical Support */
- /* Apple Computer, Inc. */
- /* 09/24/91 */
- /*______________________________________________________*/
-
- #include <GestaltEqu.h>
- #include <Memory.h>
- #include <OSEvents.h>
- #include <Sound.h>
- #include <SoundInput.h>
- #include <StdIO.h>
- #include <Types.h>
-
- //The smaller buffSize, the sooner the echo, but the more clicks you hear
- #define kbuffSize 0x10000
-
- /*The HeaderSize constant is used to skip 20 bytes of the buffer when calling bufferCmd.
- The first 20 byte of the sound header need to be skipped so that the bufferCmd will be
- pointing at a SoundHeader Record and not an 'snd ' resource header. */
- #define kHeaderSize 20
-
- // Forward reference
- pascal void MyRecComp (SPBPtr inParamPtr);
-
- typedef struct {
- short OnOff;
- short Level;
- short Length;
- } Level;
-
-
- void BufPlay (Handle Buf, SndChannelPtr channel)
-
- /*This routine takes an snd buffer and a sound channel and turns the information into a
- bufferCmd to the channel. */
-
- {
- SndCommand localSndCmd;
- OSErr err;
-
- localSndCmd.cmd = bufferCmd;
- localSndCmd.param1 = 0;
- localSndCmd.param2 = (long) ((*Buf) + kHeaderSize);
-
- err = SndDoCommand (channel, &localSndCmd, false);
- if (err != noErr)
- Debugger();
- return;
- }
-
- Handle SetUpSounds (Handle Buf, short *HeaderSize, Fixed sampRate)
-
- /* SetUpSounds is a routine which takes a buffer handle, sound headers size and sample rate
- value and turns it into a snd buffer with the proper header. It then returns the buffer
- handle back to the caller. */
-
- {
- OSErr err;
- short dummy;
-
-
- Buf = NewHandle(kbuffSize);
- if (MemError() != noErr || Buf == nil)
- Debugger();
- MoveHHi (Buf);
- if (MemError() != noErr)
- Debugger();
- HLock (Buf);
- if (MemError() != noErr)
- Debugger();
-
- /* The call to SetupSndHeader is done twice in order to make sure that the
- Header size is set correctly. */
-
- err = SetupSndHeader (Buf, 1, sampRate, 8, 'NONE', 0x3C, 0, HeaderSize);
- if (err != noErr)
- Debugger();
- err = SetupSndHeader (Buf, 1, sampRate, 8, 'NONE', 0x3C, kbuffSize - *HeaderSize, &dummy);
- if (err != noErr)
- Debugger();
-
- return (Buf);
- }
-
- main()
- {
- short dummy;
- Level myLevel;
- OSErr err;
- SPBPtr RecordRec;
- long SoundRefNum, feature;
- Handle Buffer, Buffer2, Buffer3, Buffer4;
- SndChannelPtr chan;
- short headerlength, headerlength2, headerlength3, headerlength4;
- Fixed sampleRate;
- SndCommand mycmd;
- short recordStat, MetLevel;
- unsigned long totalSampleRecord, TotalMilRecord, ActSampleRecord, ActMilRecord;
- SICompletionUPP mySICompletionUPP;
-
-
- /* use Gestalt to make sure the app will work */
-
- err = Gestalt(gestaltSoundAttr, &feature);
- if (!err) {
- if ((feature & 0x0020) != 0x0020)
- ExitToShell(); // a nice app would inform the user before quiting
- }
- else
- Debugger();
-
- /* Open sound input drive (whichever one is selected in the sound cdev) */
-
- err = SPBOpenDevice (nil, siWritePermission, &SoundRefNum);
- if (err != noErr)
- Debugger();
-
- myLevel.OnOff = 1;
- myLevel.Level = 150;
- myLevel.Length = 0;
- err = SPBSetDeviceInfo (SoundRefNum,siVoxRecordInfo, (Ptr) &myLevel);
- if (err != noErr)
- Debugger();
-
- myLevel.OnOff = 1;
- myLevel.Level = 50;
- myLevel.Length = 100;
- err = SPBSetDeviceInfo (SoundRefNum,siVoxStopInfo, (Ptr) &myLevel);
- if (err != noErr)
- Debugger();
-
- /* Get the sample rate information for the snd header */
-
- err = SPBGetDeviceInfo (SoundRefNum,siSampleRate, (Ptr) &sampleRate);
- if (err != noErr)
- Debugger();
-
- /* build the four snd buffers */
-
- Buffer = SetUpSounds (Buffer, &headerlength, sampleRate);
- Buffer2 = SetUpSounds (Buffer2, &headerlength2, sampleRate);
- Buffer3 = SetUpSounds (Buffer3, &headerlength3, sampleRate);
- Buffer4 = SetUpSounds (Buffer4, &headerlength4, sampleRate);
-
- /* build the RecordRec pointer and fill in the fields */
-
- RecordRec = (SPBPtr) NewPtr(sizeof (SPB));
- if (MemError() != noErr || RecordRec == nil)
- Debugger();
-
- /* create a Sound input completion UPP */
- mySICompletionUPP = NewSICompletionProc(MyRecComp);
-
- RecordRec->inRefNum = SoundRefNum;
- RecordRec->count = kbuffSize - headerlength;
- RecordRec->milliseconds = 0;
- RecordRec->bufferLength = kbuffSize - headerlength;
- RecordRec->bufferPtr = (Ptr) ((*Buffer) + headerlength);
- RecordRec->completionRoutine = mySICompletionUPP;
- RecordRec->interruptRoutine = nil;
- RecordRec->userLong = 0;
- RecordRec->error = 0;
- RecordRec->unused1 = 0;
-
- /* open the sound channel which I will need to play from */
-
- chan = nil;
- err = SndNewChannel (&chan, sampledSynth, 0, nil);
- if (err != noErr)
- Debugger();
-
- do { /* main loop of the app */
- err = SPBRecord (RecordRec, true); // start recording
- if (err != noErr)
- Debugger();
-
- /* The set of if-then-else statements are to determine if the first three buffers
- have been filled with recorded sounds. If so then which buffer was the last buffer
- to be filled and set the appropriate buffer to be the next buffer to be played. */
-
- if ((RecordRec->userLong & 0x00000008) == 0x00000008) {
- if (RecordRec->bufferPtr == (Ptr) ((*Buffer) + headerlength)) {
- err = SetupSndHeader (Buffer3, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
- if (err != noErr)
- Debugger();
-
- BufPlay (Buffer3, chan);
- }
- else if (RecordRec->bufferPtr == (Ptr) ((*Buffer2) + headerlength2)) {
- err = SetupSndHeader (Buffer4, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
- if (err != noErr)
- Debugger();
-
- BufPlay (Buffer4, chan);
- }
- else if (RecordRec->bufferPtr == (Ptr) ((*Buffer3) + headerlength3)) {
- err = SetupSndHeader (Buffer, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
- if (err != noErr)
- Debugger();
-
- BufPlay (Buffer, chan);
- }
- else {
- err = SetupSndHeader (Buffer2, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
- if (err != noErr)
- Debugger();
-
- BufPlay (Buffer2, chan);
- }
- }
-
- do { /* loop until the recording is done on current buffer */
- } while ((RecordRec->userLong & 0x00000001) == 0);
-
- // Use this for testing the resulting recorded sound, but only when testing
-
- err = SPBGetRecordingStatus(SoundRefNum, &recordStat, &MetLevel, &totalSampleRecord,
- &ActSampleRecord, &TotalMilRecord, &ActMilRecord);
- if (err != noErr)
- Debugger();
-
- /* Once the Completion rountine has been called I need to set up the next buffer
- to be recorded into. I do this by going through the if-then-else cases to see
- which buffer was last filled and set up the next buffer. */
-
- if (RecordRec->bufferPtr == (Ptr) ((*Buffer) + headerlength))
- RecordRec->bufferPtr = (Ptr) ((*Buffer2) + headerlength2);
-
- else if (RecordRec->bufferPtr == (Ptr) ((*Buffer2) + headerlength2))
- RecordRec->bufferPtr = (Ptr) ((*Buffer3) + headerlength3);
-
- else if (RecordRec->bufferPtr == (Ptr) ((*Buffer3) + headerlength3))
- RecordRec->bufferPtr = (Ptr) ((*Buffer4) + headerlength4);
-
- else
- RecordRec->bufferPtr = (Ptr) ((*Buffer) + headerlength);
-
- /* I need to reset the recording current buffer field*/
-
- RecordRec->userLong &= 0xFFFFFFFE;
-
- /* When the mouse button is found down, it is time to quit */
-
- } while (!Button());
-
- /* Once I am out of the loop it is time to clean up - stop the currently playing sound,
- Dispose of the Channel, close the input driver, and dispose of the buffer handles and
- RecordRec Ptr. */
-
- mycmd.cmd = quietCmd;
- mycmd.param1 = 0;
- mycmd.param2 = 0;
-
- err = SndDoImmediate (chan, &mycmd);
- if (err != noErr)
- Debugger();
-
- err = SndDisposeChannel (chan,false);
- if (err != noErr)
- Debugger();
-
- SPBCloseDevice (SoundRefNum);
-
- HUnlock (Buffer);
- HUnlock (Buffer2);
- HUnlock (Buffer3);
- HUnlock (Buffer4);
- DisposeHandle (Buffer);
- DisposeHandle (Buffer2);
- DisposeHandle (Buffer3);
- DisposeHandle (Buffer4);
- DisposePtr ((Ptr) RecordRec);
-
- DisposeRoutineDescriptor(mySICompletionUPP);
- }
- /**********************************/
-
- pascal void MyRecComp (SPBPtr inParamPtr)
-
- /* This is the Completion Routine which is called every time the buffer, which is being
- recorded into, is full. */
-
- {
- long local;
-
- local = inParamPtr->userLong;
-
- local &= 0x00000038;
-
- /* I need to check for the first three times this routine is called so I know when it
- is safe to start playing buffers. */
-
- if (local != 0x00000008) {
- if (local == 0x00000000)
- local = 0x00000010;
- else if (local == 0x00000010)
- local = 0x00000020;
- else
- local = 0x00000008;
- }
-
- inParamPtr->userLong &= 0xFFFFFFC5;
- inParamPtr->userLong |= local;
-
- /* inform the app that the recording is done */
-
- inParamPtr->userLong |= 0x00000001;
-
- return;
- }
-
- /**********************************/
- /* Bit definitions .....
- 31
- 30
- 29
- 28
- 27
- 26
- 25
- 24
- 23
- 22
- 21
- 20
- 19
- 18
- 17
- 16
- 15
- 14
- 13
- 12
- 11
- 10
- 09
- 08
- 07
- 06
- 05 - finished recording to the second buffer
- 04 - finished recording to the first buffer
- 03 - finished recording to the first three buffers
- 02
- 01
- 00 - finished recording to current buffer
- */